package rmi_impl;


import gui.GUIMain;

import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.Random;

import javax.swing.ImageIcon;

import rmi.Answer;
import rmi.Question;
import rmi.Session;
import structure.Exam;
import structure.Student;

public class SessionClass extends UnicastRemoteObject implements Session, Unreferenced{

	private static final long serialVersionUID = 1L;
	private Student object;
	private Exam exam;
	private boolean canDoExam;
	private long startTime;
	private LoginClass parent;
	
	protected SessionClass(Student stu, LoginClass parent) throws RemoteException {
		super();
		this.object = stu;
		this.exam = null;
		this.canDoExam = false;
		this.startTime = -1;
		this.parent = parent;
	}
	
	public void setExam(Exam exam){
		this.exam = exam;
	}
	
	public void setCanDoExam(boolean canDo){
		this.canDoExam = canDo;
		startTime = System.currentTimeMillis()/1000;
	}
	
	public Student getStudent(){
		return this.object;
	}

	@Override
	public void unreferenced() {
		try {
			System.out.println("logout " + object.getFirstName() + " " + object.getLastName());
			unexportObject(this, true);
		} catch (NoSuchObjectException e) {
			e.printStackTrace();
		}
	}

	@Override
	public boolean logout() throws RemoteException {
		System.out.println("logout " + object.getFirstName() + " " + object.getLastName());
		UnicastRemoteObject.unexportObject(this, true);//need check
		parent.removeStudent(this);
		return true;
	}
	
	public int getSID(){
		return object.getiD();
	}

	@Override
	public String getMSTS() throws RemoteException {
		return object.getMSTS();
	}

	@Override
	public String getStudentFirstName() throws RemoteException {
		return object.getFirstName();
	}
	
	@Override
	public String getStudentLastName() throws RemoteException {
		return object.getLastName();
	}

	@Override
	public String getDateOfBirth() throws RemoteException {
		return object.getDateOfBirth();
	}

	@Override
	public String getCourseTitle() throws RemoteException {
		String temp;
		try {
			temp = GUIMain.getDb().getCourseByCourseID(object.getJoinedCourse()).getCourseTitle();
			return temp;
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public String getExamTitle() throws RemoteException {
		if(exam == null){
			return null;
		}
		else{
			return exam.getTitle();
		}
	}

	@Override
	public ArrayList<Question> getQuestions() throws RemoteException {
		if(exam == null){
			return null;
		}
		if(!canDoExam) return null;
		ArrayList<Question> temp = new ArrayList<Question>();
		try {
			temp = GUIMain.getDb().getQuestionsByExam(exam.getExamID());
			if(temp == null) return null;
			return temp;
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public long getRemainTime() throws RemoteException {
		if(!canDoExam){
			return -1;
		}else{
			return (exam.getExamTime() - (System.currentTimeMillis()/1000 - startTime));
		}
	}

	@Override
	public boolean answerAQuestion(int answerID) throws RemoteException {
		if(!canDoExam) return false;
		try {
			Question quest = GUIMain.getDb().getQuestionsByAnswer(answerID);
			for(Entry<Integer, Answer> e : quest.getMapAnswers().entrySet()){
				if(GUIMain.getDb().CheckExistAnswer(object.getiD(), e.getKey())){
					GUIMain.getDb().DeleteStudentLogOnce(object.getiD(), e.getKey());
				}
			}
			GUIMain.getDb().InsertStudentLog(object.getiD(), answerID);
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public double getMark() throws RemoteException, SQLException {
		return GUIMain.getDb().getMarkofStudent(object.getiD());
	}

	@Override
	public boolean canDoExam() throws RemoteException {
		try {
			if(GUIMain.getDb().getMarkofStudent(object.getiD())!=-1){
				return false;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return canDoExam;
	}

	@Override
	public void requestMarking() throws RemoteException, SQLException {
		LinkedHashMap<Integer, Answer> answeredQuestion = GUIMain.getDb().getAnswersByStudentID(object.getiD());
		int numoftrue = 0;
		for(Entry<Integer, Answer> count : answeredQuestion.entrySet()){
			int trueAnswer;
			trueAnswer = GUIMain.getDb().GetTrueAnswerByQuestion(count.getValue().getQuestionId());
			if(trueAnswer == count.getKey().intValue()){
				numoftrue++;
			}
		}
		int numofquestion = GUIMain.getDb().getQuestionsByExam(exam.getExamID()).size();
		double mark = (((double)numoftrue)/numofquestion)*10;
		
		GUIMain.getDb().UpdateStudent(object.getiD(), object.getMSTS(), object.getFirstName(), object.getLastName(),
				object.getDateOfBirth(), object.getCMND(), object.getJoinedCourse(),
				mark, object.getUsername(), object.getPassword());
		canDoExam = false;
	}

	@Override
	public int getAnsweredAnswer(int qID) throws RemoteException {
		try {
			LinkedHashMap<Integer, Answer> eq = GUIMain.getDb().getAnswersByStudentID(object.getiD());
			for(Entry<Integer, Answer> count : eq.entrySet()){
				if(count.getValue().getQuestionId() == qID){
					return count.getKey();
				}
			}
			return -1;
		} catch (SQLException e) {
			return -1;
		}
		
	}

	@Override
	public String getCMND() throws RemoteException {
		return object.getCMND();
	}

	@Override
	public LinkedHashMap<Integer, String> getRandomList()
			throws RemoteException, SQLException {
		return GUIMain.getDb().getAllQuestionTypes();
	}

	@Override
	public LinkedHashMap<Integer, Question> getRandomQuestion(int list)
			throws RemoteException, SQLException {
		ArrayList<Question> ques = GUIMain.getDb().getQuestionsByType(list);
		ArrayList<Question> selectableQuestions = new ArrayList<>(); 
		for(Question count : ques){
			if(count.getPriority()== 0) continue;
			else{
				selectableQuestions.add(count);
			}
		}
		LinkedHashMap<Integer, Question> randomedQuestion  = new LinkedHashMap<>();
		if(selectableQuestions.size() == 0){
			return randomedQuestion;
		}
		Random rand = new Random();
		int randomNum = rand.nextInt(selectableQuestions.size());
		
		int trueAnswer = GUIMain.getDb().GetTrueAnswerByQuestion(selectableQuestions.get(randomNum).getQuestionID());
		randomedQuestion.put(trueAnswer, selectableQuestions.get(randomNum));
		return randomedQuestion;
	}

	@Override
	public ImageIcon getImage(int qid) throws RemoteException {
		String url;
		try {
			url = GUIMain.getDb().getQuestionsByQuestionID(qid).getQuestionImageLink();
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
		if(url.trim().equals("")){
			return null;
		}else{
			ImageIcon c = new ImageIcon(url);
			return c;
		}
	}

	@Override
	public String getRoom() throws RemoteException {
		try {
			String room = GUIMain.getDb().getCourseByCourseID(object.getJoinedCourse()).getRoom();
			return room;
		} catch (SQLException e) {
			e.printStackTrace();
			return "";
		}
	}
}
